﻿namespace PugLib.Threading
{
	/*
 * // *
// * Copyright (C) 2005 Roger Alsing : http://www.rogeralsing.com
// *
// * This library is free software; you can redistribute it and/or modify it
// * under the terms of the GNU Lesser General Public License 2.1 or later, as
// * published by the Free Software Foundation. See the included license.txt
// * or http://www.gnu.org/copyleft/lesser.html for details.
// *
// *
 * 
                SAMPLE USAGE
 
                //declare the variables we want to assign
                string str = null;
                int val = 0;

                //start a new async fork
                //assign the variables inside the fork 

                Fork.Begin()
                    .Enqueue(() => str = CallSomeWebService (123,"abc") )
                    .Enqueue(() => val = ExecSomeStoredProc ("hello") )
                    .End(); 

                //the fork has finished 

                //we can use the variables now
                Console.WriteLine("{0} {1}", str, val);
 
 */
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Threading;

	public class Fork
	{
		private readonly List<Action> _calls = new List<Action>();

		/// <summary>
		/// Starts an async fork
		/// </summary>
		/// <returns>Returns a new fork instance</returns>
		public static Fork Begin()
		{
			return new Fork();
		}

		/// <summary>
		/// Queues a call in the fork
		/// </summary>
		/// <param name="call">Delegate that should be executed async</param>
		/// <returns>Returns self</returns>
		public Fork Enqueue(Action call)
		{
			_calls.Add(call);
			return this;
		}

		/// <summary>
		/// Executes all the calls async and waits untill all of them are finished
		/// </summary>
		public void End()
		{
			//convert all calls to running threads
			//then wait for all threads to finish
			_calls.Select(call => GetThread(call))
				.ToList()
				.ForEach(thread => thread.Join());
		}

		private static Thread GetThread(Action call)
		{
			Thread thread = new Thread(GetThreadStart(call)) { IsBackground = true };
			thread.Start();
			return thread;
		}

		private static ThreadStart GetThreadStart(Action call)
		{
			ThreadStart ts = () => call();
			return ts;
		}
	}
}